from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager import time
Let's create a web app for PNG Images processing. It needs to: Allow users to upload PNG images look for ".png" extension in the submitted files make sure the magic bytes match (not sure what this is exactly but wikipedia says that the first few bytes contain 'PNG' in hexadecimal: "50 4E 47" ) after validation, store the uploaded files so that the admin can retrieve them later and do the necessary processing.
所以我們知道後端驗證檔案是否為 png 的方法有二,其一為檢查文件後綴名是否為.png;其二為驗證文件的 magic bytes,看文件在十六進制中的前幾個位元組是否為50 4E 47。
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +---------------------------------------------------- A | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z B | B C D E F G H I J K L M N O P Q R S T U V W X Y Z A C | C D E F G H I J K L M N O P Q R S T U V W X Y Z A B D | D E F G H I J K L M N O P Q R S T U V W X Y Z A B C E | E F G H I J K L M N O P Q R S T U V W X Y Z A B C D F | F G H I J K L M N O P Q R S T U V W X Y Z A B C D E G | G H I J K L M N O P Q R S T U V W X Y Z A B C D E F H | H I J K L M N O P Q R S T U V W X Y Z A B C D E F G I | I J K L M N O P Q R S T U V W X Y Z A B C D E F G H J | J K L M N O P Q R S T U V W X Y Z A B C D E F G H I K | K L M N O P Q R S T U V W X Y Z A B C D E F G H I J L | L M N O P Q R S T U V W X Y Z A B C D E F G H I J K M | M N O P Q R S T U V W X Y Z A B C D E F G H I J K L N | N O P Q R S T U V W X Y Z A B C D E F G H I J K L M O | O P Q R S T U V W X Y Z A B C D E F G H I J K L M N P | P Q R S T U V W X Y Z A B C D E F G H I J K L M N O Q | Q R S T U V W X Y Z A B C D E F G H I J K L M N O P R | R S T U V W X Y Z A B C D E F G H I J K L M N O P Q S | S T U V W X Y Z A B C D E F G H I J K L M N O P Q R T | T U V W X Y Z A B C D E F G H I J K L M N O P Q R S U | U V W X Y Z A B C D E F G H I J K L M N O P Q R S T V | V W X Y Z A B C D E F G H I J K L M N O P Q R S T U W | W X Y Z A B C D E F G H I J K L M N O P Q R S T U V X | X Y Z A B C D E F G H I J K L M N O P Q R S T U V W Y | Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Z | Z A B C D E F G H I J K L M N O P Q R S T U V W X Y
Cipher: UFJKXQZQUNB Key: SOLVECRYPTO
這題是一個維吉尼亞密碼。維吉尼亞密碼(法語:Chiffre de Vigenère,又譯維熱納爾密碼)是使用一系列凱撒密碼組成密碼字母表的加密算法,屬於多表密碼的一種簡單形式。維基百科 解密的方式也很簡單,最上面一列是明文,最左邊那行是 KEY,這樣對應起來中間的字元就是密文。知道了這個之後回推回去就可以得到明文。
1 2 3 4 5 6 7 8 9 10 11 12 13
cipher = "UFJKXQZQUNB" key = "SOLVECRYPTO"
pt = ""
for i inrange(len(cipher)): shift = ord(key[i]) - 65# 獲取密鑰字母的偏移量 c = ord(cipher[i]) # 獲取密文當中目前的字母
這題是個 RSA 加密,先來複習一下 RSA 加密裡面的各個參數。 :::info Find two prime numbers p & q n = p _ q phi(n) = (p-1) _ (q-1) e is the encryption exponent d = e^-1 mod phi(n) c is the encrypted message; c = m^e mod n m is the message; m = c^d mod n Public key = (e, n) Private key = (d, n) ::: 複習完後,看一下題目的說明。
1 2 3 4 5 6 7
Description: In RSA, a small e value can be problematic, but what about N? Can you decrypt this? ============================== Decrypt my super sick RSA: c: 421345306292040663864066688931456845278496274597031632020995583473619804626233684 n: 631371953793368771804570727896887140714495090919073481680274581226742748040342637 e: 65537
這題的敘述中告訴我們,當 e 太小的時候我們可以使用小公鑰指數攻擊(Low public exponent attack),而題目要我們思考當 N 太小的時候我們可以如何利用。
回去看一下 RSA 加密的流程後,我們發現 N 是兩個質數的乘積,而當 N 太小的時候我們就可以暴力破解出兩個 P 跟 Q。這裡我們直接使用 FactorDB 去找 N 的因數,就可以找到 P 和 Q 了。
而有了 P 和 Q,我們就可以順著 RSA 流程找到明文 M 了,我寫了個 Python 幫我找出明文,如下
c = 421345306292040663864066688931456845278496274597031632020995583473619804626233684 n = 631371953793368771804570727896887140714495090919073481680274581226742748040342637 e = 65537
# From Factor db find p and q f = FactorDB(n) f.connect() factors = f.get_factor_list() p = factors[0] q = factors[1]
phi_n = (p - 1) * (q - 1)
d = inverse(e, phi_n) print(f"Private key: d = {d}") m = pow(c, d, n) print(f"Decrypted message: m = {long2str(m)}")
最後找到的明文會是一個很大的數字,這時候再用 Crypto.Util.number 的 long_to_bytes 並 decode,將其轉為字符串,就可以得到 flag 了。
當我們把題目給的密文拿去解密,他會說Will not decrypt the ciphertext. Try Again。代表題目的這支程式應該是在偵測我們輸入的是否為 Ciphertext。而我們知道
所以我們利用題目給的 c 和 n 相加後,輸入到他的程式會得到:
1
Here you go: 290275030195850039473456618367455885069965748851278076756743720446703314517401359267322769037469251445384426639837648598397
接著只要再利用 Crypto 的 long_to_bytes3 方法就可以找到明文,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
from Crypto.Util.number import long_to_bytes from pwn import *
r = remote("mercury.picoctf.net", 10333) r.recvuntil("n:") n = int(r.recvline().strip()) r.recvuntil("ciphertext:") c = int(r.recvline().strip()) num = n + c r.sendline(str(num)) r.recvuntil("Here you go:") m = int(r.recvline().strip()) r.close()
******************Welcome to our OTP implementation!****************** This is the encrypted flag! 551e6c4c5e55644b56566d1b5100153d4004026a4b52066b4a5556383d4b0007
不難發現,這題的公鑰指數 e 超小,只有 3。所以我們使用小公鑰指數攻擊(Coppersmith’s attack, Low public exponent attack)。由於題目有說略大於,故其解題原理如下(為密文,為明文,是公鑰指數,是公鑰模數):
為了計算明文,我寫了一個 Python 腳本,如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import gmpy2 from Crypto.Util.number import long_to_bytes
# 宣告題目所給的n, e, c n = 1615765684321463054078226051959887884233678317734892901740763321135213636796075462401950274602405095138589898087428337758445013281488966866073355710771864671726991918706558071231266976427184673800225254531695928541272546385146495736420261815693810544589811104967829354461491178200126099661909654163542661541699404839644035177445092988952614918424317082380174383819025585076206641993479326576180793544321194357018916215113009742654408597083724508169216182008449693917227497813165444372201517541788989925461711067825681947947471001390843774746442699739386923285801022685451221261010798837646928092277556198145662924691803032880040492762442561497760689933601781401617086600593482127465655390841361154025890679757514060456103104199255917164678161972735858939464790960448345988941481499050248673128656508055285037090026439683847266536283160142071643015434813473463469733112182328678706702116054036618277506997666534567846763938692335069955755244438415377933440029498378955355877502743215305768814857864433151287 e = 3 c = 1220012318588871886132524757898884422174534558055593713309088304910273991073554732659977133980685370899257850121970812405700793710546674062154237544840177616746805668666317481140872605653768484867292138139949076102907399831998827567645230986345455915692863094364797526497302082734955903755050638155202890599808147130204332030239454609548193370732857240300019596815816006860639254992255194738107991811397196500685989396810773222940007523267032630601449381770324467476670441511297695830038371195786166055669921467988355155696963689199852044947912413082022187178952733134865103084455914904057821890898745653261258346107276390058792338949223415878232277034434046142510780902482500716765933896331360282637705554071922268580430157241598567522324772752885039646885713317810775113741411461898837845999905524246804112266440620557624165618470709586812253893125417659761396612984740891016230905299327084673080946823376058367658665796414168107502482827882764000030048859751949099453053128663379477059252309685864790106
# 暴力破解 k * n + c 的 e 次方根 k = 1 whileTrue: m, is_root = gmpy2.iroot(k * n + c, e) if is_root: break else: k += 1
FILE *f = fopen("flag.txt", "r"); if (f == NULL) { printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n"); exit(0); }
fgets(flag, FLAGSIZE_MAX, f); signal(SIGSEGV, sigsegv_handler); // Set up signal handler 當運行時出現Signal: SIGSEGV (Segmentation fault)時會調用sigsegv_handler函數
gid_t gid = getegid(); setresgid(gid, gid, gid);
printf("Input: "); fflush(stdout); char buf1[100]; gets(buf1); vuln(buf1); printf("The program will exit now\n"); return0; }